Lógica de Programação com Javascript

Aula 15 - Callback



Helder Jefferson Ferreira da Luz

helder.luz@ifpr.edu.br

Objetivos

  • Entender o conceito de funções de callback
  • Conhecer as diferentes formas de declarar uma função
  • Aprender a utilizar os métodos de array que utilizam callback (forEach, map, filter, reduce, sort)

Formas de declarar uma função

Até agora, vimos a declaração de função usando a palavra-chave function. Existem outras formas, cada uma com suas particularidades. Vamos ver as três principais:

  • Declaração de Função (Function Declaration)
  • Expressão de Função (Function Expression)
  • Função de Seta (Arrow Function)

Formas de declarar uma função

1. Declaração de Função (Function Declaration)

function soma(a, b) {
  return a + b;
}
  • Esta é a forma clássica.
  • A principal característica é o hoisting (içamento): a função pode ser chamada no código antes mesmo de sua declaração.

Formas de declarar uma função

2. Expressão de Função (Function Expression)

const soma = function(a, b) {
  return a + b;
};
  • A função é atribuída a uma variável ou constante.
  • Não sofre hoisting: só pode ser chamada após a linha em que foi definida.
  • Pode ser anônima (sem nome após function).

Formas de declarar uma função

3. Função de Seta (Arrow Function)

const soma = (a, b) => a + b;
  • Sintaxe mais curta e moderna, introduzida no ES6.
  • Não sofre hoisting.
  • Não possui seu próprio this, arguments, super ou new.target. Herda o this do escopo em que foi criada. Com isso, não deve ser usada para criar métodos.
  • Ideal para callbacks e funções curtas.

Arrow Functions - Sintaxe Opcional

A sintaxe das arrow functions pode ser ainda mais concisa em certas situações:

  1. Parênteses () são opcionais para um único parâmetro:

    // Com parênteses
    const dobrar = (n) => n * 2;
    
    // Sem parênteses (quando há apenas um parâmetro)
    const dobrar = n => n * 2;
    
  2. Chaves {} e return são opcionais para um corpo com uma única expressão:

    // Com chaves e return explícito
    const soma = (a, b) => {
      return a + b;
    };
    
    // Sem chaves e com return implícito
    const soma = (a, b) => a + b;
    

O que é uma função de Callback?

Uma função de callback é uma função que é passada como argumento para outra função, para ser "chamada de volta" (called back) em um momento posterior.

  • Podem ser atribuídas a variáveis.
  • Podem ser passadas como argumentos para outras funções.
  • Podem ser retornadas por outras funções.

O que é uma função de Callback?

Exemplo de função callback
function executarDepoisDe2s(callback) {
  setTimeout(() => { // Recebe uma função e a chama após 2 segundos
    callback('Callback executado após 2s');
  }, 2000);
}

function imprimeMensagem(mensagem) {
  console.log(mensagem);
}

executarDepoisDe2s(imprimeMensagem);

// executarDepoisDe2s((mensagem) => {
//   console.log(mensagem);
// });

Arrays e Callbacks

Muitos métodos de array em JavaScript utilizam funções de callback para realizar operações em seus elementos. Vamos ver os principais.

Arrays - forEach

Executa uma função de para cada elemento do array. É uma alternativa aos laços for.

Sintaxe
array.forEach(função(elementoAtual, índice, array))
Exemplo
const numeros = [1, 2, 3, 4, 5];

// Usando uma função de seta como callback
numeros.forEach((numero, indice) => {
    console.log(`Índice: ${indice}, Valor: ${numero}`);
});

// O resultado é o mesmo que usar um laço for:
for (let i = 0; i < numeros.length; i++) {
    console.log(`Índice: ${i}, Valor: ${numeros[i]}`);
}

Arrays - forEach

Exemplo com lista de objetos
const pessoas = [
  { nome: 'Ana', idade: 22 },
  { nome: 'Bia', idade: 25 },
  { nome: 'Carlos', idade: 30 },
  { nome: 'Daniel', idade: 35 }
]

pessoas.forEach((pessoa, indice) => {
  console.log(`${indice + 1}. ${pessoa.nome} tem ${pessoa.idade} anos.`)
})

Arrays - map

Cria um novo array com os resultados da chamada de uma função de callback para cada elemento do array original.


Sintaxe
array.map(função(elementoAtual, índice, array))

Arrays - map

Exemplo
const numeros = [1, 2, 3, 4, 5];

const dobrados = numeros.map((numero) => {
  return numero * 2;
});

console.log(dobrados); // [2, 4, 6, 8, 10]
console.log(numeros);  // [1, 2, 3, 4, 5] (o original não é modificado)

Arrays - filter

Cria um novo array com todos os elementos que passaram no teste implementado pela função de callback.


Sintaxe
array.filter(função(elementoAtual, índice, array))

Arrays - filter

Exemplo
const numeros = [1, 2, 3, 4, 5, 6];

const pares = numeros.filter((numero) => {
  return numero % 2 === 0;
});

console.log(pares); // [2, 4, 6]

Arrays - find

Retorna o primeiro elemento do array que satisfaz a condição da função de callback. Se nenhum elemento for encontrado, retorna undefined.


Sintaxe
array.find(função(elementoAtual, índice, array))

Arrays - find

Exemplo
const numeros = [10, 4, 25, 18, 7];

const primeiroMaiorQue20 = numeros.find((numero) => {
  return numero > 20;
});

console.log(primeiroMaiorQue20); // 25

const maiorQue30 = numeros.find(n => n > 30);
console.log(maiorQue30); // undefined

Arrays - reduce

Executa uma função "redutora" em cada elemento do array, resultando em um único valor de retorno.


Sintaxe
array.reduce(callback(acumulador, elementoAtual, indice, array), valorInicial)

Arrays - reduce

Exemplo - somando todos os elementos
const numeros = [1, 2, 3, 4, 5];

const soma = numeros.reduce((acumulador, numero) => {
  return acumulador + numero;
}, 0); // 0 é o valor inicial do acumulador

console.log(soma); // 15

Arrays - sort

Ordena os elementos de um array no próprio array e retorna o array ordenado.
A ordenação padrão é baseada em strings.


Sintaxe
array.sort(callback(primeiroElemento, segundoElemento))

Arrays - sort

Exemplo - números (use função de comparação)
const numeros = [10, 1, 21, 3];

// Ordenação crescente
numeros.sort((a, b) => a - b);
console.log(numeros); // [1, 3, 10, 21]

// Ordenação decrescente
numeros.sort((a, b) => b - a);
console.log(numeros); // [21, 10, 3, 1]

Arrays - sort

Exemplo - ordenando uma lista de objetos
const pessoas = [
  { nome: 'Carlos', idade: 30 },
  { nome: 'Bia', idade: 25 },
  { nome: 'Daniel', idade: 35 },
  { nome: 'Ana', idade: 22 },
]

pessoas.sort((a, b) => a.idade - b.idade)
console.log(pessoas) // Array original ordenado

// Usando toSorted (ES2023) para não modificar o array original
console.log(pessoas.toSorted((a, b) => a.idade - b.idade)) // Novo array ordenado

Dúvidas? 🤔

Exercícios

  1. Crie uma função executarCallback(callback) que recebe uma função como argumento e a executa. Teste-a passando uma função que imprime "Callback executado!".
  2. Dado o array
    const pessoas = [
      { nome: 'Ana', idade: 25 }, 
      { nome: 'Bruno', idade: 30 }, 
      { nome: 'Carla', idade: 22 }
    ];
    
    Use map para criar um novo array contendo apenas os nomes das pessoas.

Exercícios

  1. Dado o array const numeros = [10, 21, 3, 8, 15];, use filter para criar um novo array contendo apenas os números maiores que 10.
  2. Usando o array de números do exercício anterior, use find para encontrar o primeiro número que é maior que 20.
  3. Dado o array const numeros = [1, 2, 3, 4, 5];, use reduce para calcular a soma de todos os números.
  4. Dado o array const palavras = ['gato', 'cachorro', 'elefante', 'pássaro'];, use sort para ordená-lo em ordem alfabética.

Exercícios

  1. Implemente uma função que apresente o resultado da equação exponencial x2 de cada número de um array.
  2. Implemente uma função que receba um vetor de números e retorne um vetor de Strings.
  3. Faça uma função que retorne todos os números impares de um array.

Exercícios

  1. Faça uma função que conte o número de pessoas que votaram em uma eleição. Ele deve receber um vetor de objetos que possui dois atributos: “nome” e “votou”. “votou” deve possuir valor “true” ou “false”.
    const eleitores = [
      { nome: 'Ana Silva', votou: true },
      { nome: 'Bruno Santos', votou: false },
      { nome: 'Carla Souza', votou: true },
      { nome: 'Diego Lima', votou: true },
      { nome: 'Eduarda Alves', votou: false },
      { nome: 'Felipe Rocha', votou: true },
      { nome: 'Gustavo Pereira', votou: false },
      { nome: 'Helena Costa', votou: true },
      { nome: 'Igor Martins', votou: false },
      { nome: 'Júlia Oliveira', votou: true }
    ];
    

Exercícios

  1. Dado um array de produtos, crie uma função que filtre os produtos que custam mais de R$ 50 e retorne um novo array apenas com os nomes desses produtos.

    const produtos = [
      { nome: 'Teclado', preco: 120 },
      { nome: 'Mouse', preco: 45 },
      { nome: 'Monitor', preco: 750 },
      { nome: 'Cadeira Gamer', preco: 1500 },
      { nome: 'Mousepad', preco: 30 }
    ];
    
  2. Dado o array de produtos acima, use reduce para calcular o valor total de todos os produtos no carrinho.

Exercícios

  1. Crie uma função que receba um array de usuários e um id. A função deve usar find para retornar o objeto do usuário com o id correspondente. Se não encontrar, deve retornar a mensagem "Usuário não encontrado".
    const usuarios = [
      { id: 1, nome: 'Alice' },
      { id: 2, nome: 'Bob' },
      { id: 3, nome: 'Charlie' }
    ];
    
  2. Dado um array de alunos, ordene-o em ordem decrescente de notas.
    const alunos = [
      { nome: 'Ana', nota: 8.5 },
      { nome: 'Bruno', nota: 9.2 },
      { nome: 'Carla', nota: 7.8 },
      { nome: 'Daniel', nota: 9.5 }
    ];
    

Em JavaScript, funções são "cidadãos de primeira classe", o que significa que podem ser tratadas como qualquer outro valor:

##### Sintaxe `array.reduce(callback(acumulador, valorAtual, indice, array), valorInicial)`